package com.area.cth.service.impl;

import com.area.cth.mapper.CollectMapper;
import com.area.cth.mapper.GoodsMapper;
import com.area.cth.mapper.UserMapper;
import com.area.cth.pojo.Collect;
import com.area.cth.pojo.Goods;
import com.area.cth.pojo.User;
import com.area.cth.service.RecommendationService;
import com.area.cth.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class RecommendationServiceImpl implements RecommendationService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private GoodsMapper goodsMapper;

    @Autowired
    private CollectMapper collectMapper;

    private static final Integer numRecommendations = 6;

    // 计算两个用户之间的相似度（基于Jaccard相似度）
    private double calculateSimilarity(Integer userId1, Integer userId2) {
        Set<Integer> user1GoodsIds = getUserCollectedGoodsIds(userId1);
        Set<Integer> user2GoodsIds = getUserCollectedGoodsIds(userId2);

        Set<Integer> intersection = new HashSet<>(user1GoodsIds);
        intersection.retainAll(user2GoodsIds);

        Set<Integer> union = new HashSet<>(user1GoodsIds);
        union.addAll(user2GoodsIds);

        return (double) intersection.size() / union.size();
    }

    // 获取用户收藏的商品ID集合
    private Set<Integer> getUserCollectedGoodsIds(Integer userId) {
        List<Collect> collects = collectMapper.getMyCollect(userId);
        return collects.stream()
                .map(Collect::getGoodsId)
                .collect(Collectors.toSet());
    }

    // 基于协同过滤算法推荐商品
    public List<Goods> recommendGoods() {
        Map<String, Object> map = ThreadLocalUtil.get();
        Integer userId = (Integer) map.get("id");
        Set<Integer> userCollectedGoodsIds = getUserCollectedGoodsIds(userId);

        // 获取所有用户及其收藏的商品ID
        List<User> allUsers = userMapper.selectList(null);
        Map<Integer, Set<Integer>> userGoodsMap = new HashMap<>();
        for (User user : allUsers) {
            userGoodsMap.put(user.getId(), getUserCollectedGoodsIds(user.getId()));
        }

        // 计算当前用户与其他用户的相似度，并找到最相似的K个用户
        PriorityQueue<Map.Entry<Integer, Double>> similarUsersQueue = new PriorityQueue<>(
                (e1, e2) -> Double.compare(e2.getValue(), e1.getValue())
        );
        for (Map.Entry<Integer, Set<Integer>> entry : userGoodsMap.entrySet()) {
            Integer otherUserId = entry.getKey();
            if (!otherUserId.equals(userId)) {
                double similarity = calculateSimilarity(userId, otherUserId);
                similarUsersQueue.offer(new AbstractMap.SimpleEntry<>(otherUserId, similarity));
            }
        }

        List<Map.Entry<Integer, Double>> similarUsers = new ArrayList<>(similarUsersQueue.stream()
                .limit(10) // 最相似的10个用户
                .collect(Collectors.toList()));

        // 基于相似用户的收藏来推荐商品
        Map<Integer, Integer> recommendedGoodsCounts = new HashMap<>();
        for (Map.Entry<Integer, Double> similarUser : similarUsers) {
            Integer similarUserId = similarUser.getKey();
            Set<Integer> similarUserGoodsIds = userGoodsMap.get(similarUserId);
            for (Integer goodsId : similarUserGoodsIds) {
                if (!userCollectedGoodsIds.contains(goodsId)) {
                    recommendedGoodsCounts.put(goodsId, recommendedGoodsCounts.getOrDefault(goodsId, 0) + 1);
                }
            }
        }

        // 按照推荐次数排序，并返回前numRecommendations个商品
        List<Map.Entry<Integer, Integer>> sortedRecommendedGoods = recommendedGoodsCounts.entrySet().stream()
                .sorted((e1, e2) -> Integer.compare(e2.getValue(), e1.getValue()))
                .limit(numRecommendations)
                .collect(Collectors.toList());

        List<Goods> recommendedGoods = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : sortedRecommendedGoods) {
            Goods goods = goodsMapper.getGoodsById(entry.getKey());
            recommendedGoods.add(goods);
        }

        return recommendedGoods;
    }
}
